﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using MQTTnet;
using MQTTnet.Client.Receiving;
using MQTTnet.Protocol;
using MQTTnet.Server;
using Newtonsoft.Json;
using CyzFaceBLL.Global;
using CyzFaceBLL.Common;//DNAKESystem.Common.Global;

namespace CyzFaceBLL.Helper
{
    public class MQTTBrokerHelper
    {
        /// <summary>
        /// 单例模式对像获取
        /// </summary>
        public static readonly MQTTBrokerHelper Instance = new MQTTBrokerHelper();

        private IMqttServer mqttServer = null;

        private MQTTBrokerHelper()
        {
            try
            {
                //this.Start();
            }
            catch (Exception ex)
            {
                LogWrite.TxtExport_DateNow("LogErr.txt", "MQTTBrokerHelper Err:" + ex.Message);
            }
        }

        public void Start()
        {
            try
            {
                if (!GlobalParameters.IsMQTTBroker)
                {
                    LogWrite.TxtExport_DateNow("LogTrace.txt", "未启用 Mqtt消息中间件(Broker).");
                    return;
                }
                Task.Run(() =>
                {
                    try
                    {
                        this.StartThreadRun();
                    }
                    catch (Exception ex)
                    {
                        LogWrite.TxtExport_DateNow("LogErr.txt", "MQTTBrokerHelper Start 1Err:" + ex.Message);
                    }
                });
            }
            catch (Exception ex)
            {
                LogWrite.TxtExport_DateNow("LogErr.txt", "MQTTBrokerHelper Start Err:" + ex.Message);
            }
        }

        public void StartThreadRun()
        {
            try
            {
                if (mqttServer == null)
                {
                    mqttServer = new MqttFactory().CreateMqttServer();
                }
                var options = new MqttServerOptions
                {
                    ///连接验证程序
                    ConnectionValidator = new MqttServerConnectionValidatorDelegate(p =>
                    {
                        //if (p.ClientId == "SpecialClient")
                        //{
                        //    if (p.Username != "USER" || p.Password != "PASS")
                        //    {
                        //        p.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword;
                        //        //p.ReturnCode = MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword;
                        //    }
                        //}

                        ////MqttNetConsoleLogger.PrintToConsole(
                        ////$"DN1 '{p.ClientId}' Username '{p.Username}' Password '{p.Password}'",
                        ////ConsoleColor.White);
                        p.ReasonCode = MqttConnectReasonCode.Success;
                    }),
                    //Storage = new RetainedMessageHandler(),
                    //发送应用程序消息拦截器
                    ApplicationMessageInterceptor = new MqttServerApplicationMessageInterceptorDelegate(context =>
                    {

                        ////MqttNetConsoleLogger.PrintToConsole(
                        ////$"DN2 '{context.ClientId}' reported '{context.ApplicationMessage.Topic}' > '{Encoding.UTF8.GetString(context.ApplicationMessage.Payload ?? new byte[0])}'",
                        ////ConsoleColor.Yellow);

                        //if (MqttTopicFilterComparer.IsMatch(context.ApplicationMessage.Topic, "/myTopic/WithTimestamp/#"))
                        //{
                        //    // Replace the payload with the timestamp. But also extending a JSON 
                        //    // based payload with the timestamp is a suitable use case.
                        //    context.ApplicationMessage.Payload = Encoding.UTF8.GetBytes(DateTime.Now.ToString("O"));
                        //}

                        //if (context.ApplicationMessage.Topic == "not_allowed_topic")
                        //{
                        //    context.AcceptPublish = false;
                        //    context.CloseConnection = true;
                        //}
                    }),
                    //订阅拦截器
                    SubscriptionInterceptor = new MqttServerSubscriptionInterceptorDelegate(context =>
                    {
                        //if (context.TopicFilter.Topic.StartsWith("admin/foo/bar") && context.ClientId != "theAdmin")
                        //{
                        //    context.AcceptSubscription = false;
                        //}

                        //if (context.TopicFilter.Topic.StartsWith("the/secret/stuff") && context.ClientId != "Imperator")
                        //{
                        //    context.AcceptSubscription = false;
                        //    context.CloseConnection = true;
                        //}
                    })
                };
                //收到的应用程序消息拦截器
                mqttServer.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(e =>
                {
                    //MqttNetConsoleLogger.PrintToConsole(
                    //    $"'{e.ClientId}' reported '{e.ApplicationMessage.Topic}' > '{Encoding.UTF8.GetString(e.ApplicationMessage.Payload ?? new byte[0])}'",
                    //    ConsoleColor.Magenta);
                    try
                    {
                        this.ApplicationMessageReceivedEvent?.Invoke(e, null);
                        this.Log(e, "收到应用程序消息");
                    }
                    catch (Exception ex)
                    {
                        LogWrite.TxtExport_DateNow("LogErr.txt", "MQTTBrokerHelper StartThreadRun 2Err:" + ex.Message);
                    }
                });
                mqttServer.ClientConnectedHandler = new MqttServerClientConnectedHandlerDelegate(e =>
                {
                    //MqttNetConsoleLogger.PrintToConsole("Client connected event fired.", ConsoleColor.White);
                    try
                    {
                        this.ClientConnectedEvent?.Invoke(e, null);
                        this.Log(e, "Mqtt客户端连接上来");
                    }
                    catch (Exception ex)
                    {
                        LogWrite.TxtExport_DateNow("LogErr.txt", "MQTTBrokerHelper StartThreadRun 0Err:" + ex.Message);
                    }
                });
                //客户端断开连接拦截器
                mqttServer.ClientDisconnectedHandler = new MqttServerClientDisconnectedHandlerDelegate(e =>
                {
                    //MqttNetConsoleLogger.PrintToConsole(
                    //    $"'{e.ClientId}' Disconnected ", ConsoleColor.Red);
                    try
                    {
                        this.ClientDisconnectedEvent?.Invoke(e, null);
                        this.Log(e, "Mqtt客户端断开");
                    }
                    catch (Exception ex)
                    {
                        LogWrite.TxtExport_DateNow("LogErr.txt", "MQTTBrokerHelper StartThreadRun 1Err:" + ex.Message);
                    }
                });

                mqttServer.StartAsync(options);
                //Console.WriteLine("MQTT服务启动成功！");
                LogWrite.TxtExport_DateNow("LogTrace.txt", "Mqtt消息中间件(Broker) 启动成功!");
            }
            catch (Exception ex)
            {
                LogWrite.TxtExport_DateNow("LogErr.txt", "MQTTBrokerHelper StartThreadRun Err:" + ex.Message);
            }
        }

        private void Log(object obj, string sTag)
        {
            try
            {
                string sJson = JsonConvert.SerializeObject(obj);
                string strLog = "\r\n【" + (sTag ?? "") + "】\r\n" + (sJson ?? "") + "\r\n";
                LogWrite.TxtExport_DateNow("LogTrace.txt", strLog);
            }
            catch (Exception ex)
            {
                LogWrite.TxtExport_DateNow("LogErr.txt", "MQTTBrokerHelper Log Err:" + ex.Message);
            }
        }

        public void End()
        {
            try
            {
                if (!GlobalParameters.IsMQTTBroker)
                {
                    LogWrite.TxtExport_DateNow("LogTrace.txt", "未启用 Mqtt消息中间件(Broker),无法进行停止操作!");
                    return;
                }
                if (mqttServer != null)
                {
                    Task.Run(() =>
                    {
                        try
                        {
                            mqttServer.StopAsync();
                            mqttServer = null;
                            LogWrite.TxtExport_DateNow("LogTrace.txt", "Mqtt消息中间件(Broker) 运行停止!");
                        }
                        catch (Exception ex)
                        {
                            LogWrite.TxtExport_DateNow("LogErr.txt", "MQTTBrokerHelper End 0Err:" + ex.Message);
                        }
                    });
                }
            }
            catch (Exception ex)
            {
                LogWrite.TxtExport_DateNow("LogErr.txt", "MQTTBrokerHelper End Err:" + ex.Message);
            }
        }

        /// <summary>
        /// Mqtt客户端连接上来事件(注:需拆箱)
        /// </summary>
        public event EventHandler ClientConnectedEvent;

        /// <summary>
        /// Mqtt客户端断开事件(注:需拆箱)
        /// </summary>
        public event EventHandler ClientDisconnectedEvent;

        /// <summary>
        /// 收到应用程序消息事件
        /// </summary>
        public event EventHandler ApplicationMessageReceivedEvent;
    }
}
